package com.own.component.sms.core.util.code;

import com.own.component.common.exception.BusinessException;
import com.own.component.common.exception.BusinessSimpleException;
import com.own.component.common.util.FormUtil;
import com.own.component.common.util.RandomUtil;
import com.own.component.common.util.executor.ExecutorUtil;
import com.own.component.sms.core.model.SmsCheckModel;
import com.own.component.sms.core.model.SmsResponseModel;
import com.own.component.sms.core.model.SmsSendModel;
import com.own.component.sms.core.util.SmsUtil;
import com.own.component.store.core.Store;
import com.own.component.store.core.util.base.RsaKeyUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.Duration;

/**
 * SmsCodeUtil
 * <p>
 * 短信验证码工具
 *
 * @author chenxueli
 * @date 2023-06-26 19:37:00
 */
@Slf4j
@Component
public class SmsCodeUtil {

    private static final String STORE_REGISTER_PHONE = "sms:c:p:";
    private static final String STORE_REGISTER_PHONE_COUNT = "sms:c:p:c:";
    private static final String STORE_REGISTER_PHONE_AGAIN = "sms:c:p:a:";

    @Resource
    private RsaKeyUtil rsaKeyUtil;

    @Resource
    private Store<String> store;

    @Resource
    private ExecutorUtil executorUtil;

    /**
     * 验证验证码
     *
     * @param originPhone 原始手机号
     * @param originKey   原始key
     * @param code        验证码
     * @return 是否验证通过
     */
    public SmsCheckModel verification(String originPhone, String originKey, String code) {
        // 获取真实的手机号信息
        var phone = getRealPhone(originPhone, originKey);
        // 验证手机号
        return verification(phone, code);
    }

    /**
     * 验证验证码
     *
     * @param phone 手机号
     * @param code  验证码
     * @return 是否验证通过
     */
    public SmsCheckModel verification(String phone, String code) {
        // 验证验证码信息
        var key = STORE_REGISTER_PHONE + phone;
        var storeCode = store.value().get(key);
        if (!code.equals(storeCode)) {
            return SmsCheckModel.FAIL;
        }
        // 删除验证码信息
        store.value().remove(key);
        store.value().remove(STORE_REGISTER_PHONE_COUNT + phone);
        store.value().remove(STORE_REGISTER_PHONE_AGAIN + phone);
        return new SmsCheckModel(true, phone);
    }

    /**
     * 创建验证码
     *
     * @param originPhone 原始手机号
     * @param originKey   原始key
     * @param config      配置信息
     */
    public SmsResponseModel build(String originPhone, String originKey, SmsCodeSendConfig config) {
        return build(originPhone, originKey, config, false);
    }

    /**
     * 创建验证码
     *
     * @param originPhone 原始手机号
     * @param originKey   原始key
     * @param config      配置信息
     * @param executor    指定方法
     */
    public SmsResponseModel build(String originPhone, String originKey, SmsCodeSendConfig config, boolean executor) {
        // 获取真实的手机号信息
        var phone = getRealPhone(originPhone, originKey);
        return build(phone, config, executor);
    }

    /**
     * 创建验证码
     *
     * @param phone    手机号
     * @param config   配置信息
     * @param executor 指定方法
     */
    public SmsResponseModel build(String phone, SmsCodeSendConfig config, boolean executor) {
        // 去获取最新的验证码信息
        var key = STORE_REGISTER_PHONE + phone;
        var countKey = STORE_REGISTER_PHONE_COUNT + phone;
        var againKey = STORE_REGISTER_PHONE_AGAIN + phone;
        // 验证是否已经有发送过的短信信息
        var code = store.value().get(key);
        // 是否可以再次获取验证码
        if (store.value().contains(againKey)) {
            throw new BusinessException("验证码已发送，请勿重复发送");
        }
        // 判断发送的次数
        var count = store.atomic().getAndIncrement(countKey, Duration.ofMinutes(config.getLimitTime()));
        if (count >= config.getLimitCount()) {
            throw new BusinessException("验证码发送次数过多，请稍后再试");
        }
        if (StringUtils.isBlank(code)) {
            // 生成验证码
            code = RandomUtil.getRandomString(6, "1234567890");
        }
        log.debug("手机号：{}, 验证码：{}", phone, code);
        var model = new SmsSendModel(config.getTemplateCode());
        model.add(phone);
        model.put("code", code);
        if (config.getParams() != null) {
            config.getParams().forEach(model::put);
        }
        if (executor) {
            executorUtil.execute(() -> {
                SmsUtil.send(config.getMethod(), model);
            });
        } else {
            try {
                SmsUtil.send(config.getMethod(), model);
            } catch (Exception e) {
                throw new BusinessSimpleException("验证码发送失败");
            }
        }
        // 验证码设置缓存（15分钟内有效）
        store.value().set(key, code, Duration.ofMinutes(config.getEffectiveTime()));
        // 再次发送设置缓存（15分钟内有效）
        store.value().set(againKey, code, Duration.ofMinutes(config.getAgainTime()));
        return new SmsResponseModel(phone, code);
    }

    /**
     * 获取验证码
     *
     * @param phone 手机号
     * @return 验证码
     */
    public String getCode(String phone) {
        // 验证手机号
        if (!FormUtil.isPhone(phone)) {
            log.debug("手机号：{}", phone);
            throw new BusinessException("手机号不正确");
        }
        // 验证验证码信息
        var key = STORE_REGISTER_PHONE + phone;
        return store.value().get(key);
    }

    /**
     * 获取真实的手机号信息
     *
     * @param phone 手机号
     * @param key   加密的key
     * @return 真实的手机号
     */
    public String getRealPhone(String phone, String key) {
        var content = StringUtils.isNotBlank(key) ? rsaKeyUtil.decrypt(key, phone) : phone;
        if (FormUtil.isPhone(content)) {
            return content;
        }
        throw new BusinessSimpleException("手机号格式不正确");
    }

}
